﻿using Newtonsoft.Json.Linq;
using Simple.Tools.Map;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

/*********************************************************
 * 命名空间 MDT.VirtualSoftPlatform.Common
 * 接口名称 ExpressionConvert
 * 开发人员：-nhy
 * 创建时间：2022/7/12 14:01:21
 * 描述说明：
 * 更改历史：
 * 
 * *******************************************************/
namespace Simple.Tools
{
	/// <summary>
	/// 
	/// </summary>
	public class SimpleMapper : ISimpleMapper
	{

		BaseCheckType checkType;
		/// <summary>
		/// 
		/// </summary>
		public SimpleMapper()
		{
			checkType = SimpleInitialize.GetCheckType();
		}
		/// <summary>
		/// 更新
		/// </summary>
		/// <typeparam name="TSource"></typeparam>
		/// <typeparam name="TTarget"></typeparam>
		/// <param name="source"></param>
		/// <param name="target"></param>
		public void Map<TSource, TTarget>(TSource source, TTarget target)
		{
			if (SimpleCheck.IsNull(source))
			{
				return;
			}

			Type tSource = source.GetType();
			Type tTarget = target.GetType();

			if (!tSource.IsClass || tSource == typeof(string))
			{
				if (source is TTarget result)
				{
					result = target;
				}
			}
			foreach (var item in tSource.GetProperties())
			{
				var sProp = tTarget.GetProperty(item.GetColName());
				if (SimpleCheck.IsNull(sProp))
				{
					continue;
				}
				#region map
				MapToAttribute map = null;
				if (item.IsDefined(typeof(MapToAttribute)))
				{
					map = item.GetCustomAttribute<MapToAttribute>();
				}
				else
				{
					map = new MapToAttribute(sProp.PropertyType);
				}
				#endregion

				var result = IsNull(source, item);
				if (!result)
				{
					object value = item.GetValue(source);
					if (value == null)
					{
						continue;
					}

					// 对象类型数据

					if (item.PropertyType.IsClass && item.PropertyType != typeof(string))
					{
						MapHandle(item, sProp, value, target);
					}
					else
					{
						//普通类型数据
						SetPropery(map, item, sProp, value, target);
					}
				}
			}

			foreach (var item in tSource.GetFields())
			{
				#region map
				var sField = tTarget.GetField(item.GetColName());
				MapToAttribute map = null;
				if (sField == null)
				{
					continue;
				}
				if (item.IsDefined(typeof(MapToAttribute)))
				{
					map = item.GetCustomAttribute<MapToAttribute>();
				}
				else
				{
					map = new MapToAttribute(sField.FieldType);
				}
				#endregion
				if (!IsNull(source, item))
				{
					var value = item.GetValue(source);
					if (item.FieldType.IsClass && item.FieldType != typeof(string))
					{
						//对象类型或者非值类型
						MapHandle(item, sField, value, target);
					}
					else
					{
						SetField(map, item, sField, value, target);
					}
				}
			}
		}
		/// <summary>
		///  
		/// </summary>
		/// <param name="sourceProp">原来的属性</param>
		/// <param name="targetProp">目标属性</param>
		/// <param name="sourceObj">原来的属性值</param>
		/// <param name="taregetObj"></param>
		protected void MapHandle(PropertyInfo sourceProp, PropertyInfo targetProp, object sourceObj, object taregetObj)
		{
			Type type = taregetObj.GetType();
			object targetPropValue = targetProp.GetValue(taregetObj);
			if (targetPropValue == null)
			{
				targetPropValue = Activator.CreateInstance(targetProp.PropertyType);
				targetProp.SetValue(taregetObj, targetPropValue);
			}
			MapToAttribute map = sourceProp.GetCustomAttribute<MapToAttribute>();

			if (SimpleCheck.IsNull(map))
			{
				map = new MapToAttribute(targetProp.PropertyType.GenericTypeArguments[0]);
			}
			//MethodInfo method = type.GetMethod(map.GetMethodName());
			if (sourceProp.PropertyType.Name == typeof(List<>).Name)
			{
				dynamic dyValues = sourceObj;
				dynamic dyTargets = targetPropValue;
				MethodInfo add = targetProp.PropertyType.GetMethod("Add");
				foreach (var dynamicItem in dyValues)
				{
					if (targetProp.PropertyType.GenericTypeArguments[0].IsClass && typeof(string) != targetProp.PropertyType.GenericTypeArguments[0])
					{
						var subObject = Activator.CreateInstance(targetProp.PropertyType.GenericTypeArguments[0]);
						Map(dynamicItem, subObject);
						add.Invoke(targetPropValue, new object[] { subObject });
					}
					else
					{
						add.Invoke(targetPropValue, new object[] { checkType.GetTargetValue(map, sourceProp.PropertyType.GenericTypeArguments[0], targetProp.PropertyType.GenericTypeArguments[0], dynamicItem) });
					}

					//if (!SimpleCheck.IsNull(method))
					//{
					//	method.Invoke(taregetObj,new object[] {subObject});
					//}
				}
			}
			else if (sourceProp.PropertyType.Name == typeof(Dictionary<int, int>).Name)
			{
				dynamic dyMaps = sourceObj;
				dynamic dyTargetMapss = targetPropValue;
				MethodInfo add = targetProp.PropertyType.GetMethod("Add");
				foreach (var mapItem in dyMaps)
				{
					if (targetProp.PropertyType.GenericTypeArguments[1] == typeof(string) && !sourceProp.PropertyType.GenericTypeArguments[1].IsClass)
					{
						add.Invoke(targetPropValue, new object[] { mapItem.Key, checkType.GetTargetValue(map, sourceProp.PropertyType.GenericTypeArguments[0], targetProp.PropertyType.GenericTypeArguments[0], mapItem) });
					}
					else
					{
						var subObject = Activator.CreateInstance(sourceProp.PropertyType.GenericTypeArguments[1]);
						Map(mapItem, subObject);
						add.Invoke(targetPropValue, new object[] { mapItem.Key, subObject });
					}
					//if (!SimpleCheck.IsNull(method))
					//{
					//	method.Invoke(taregetObj, new object[] { mapItem.Key,subObject });
					//}
				}
			}
			else
			{
				Map(sourceObj, targetPropValue);
			}
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="sourceProp"></param>
		/// <param name="targetProp"></param>
		/// <param name="sourceObj"></param>
		/// <param name="taregetObj"></param>
		protected void MapHandle(FieldInfo sourceProp, FieldInfo targetProp, object sourceObj, object taregetObj)
		{
			Type type = taregetObj.GetType();
			object targetPropValue = targetProp.GetValue(taregetObj);
			if (targetProp == null)
			{
				targetPropValue = Activator.CreateInstance(targetProp.FieldType);
				targetProp.SetValue(taregetObj, targetProp);
			}

			MapToAttribute map = sourceProp.GetCustomAttribute<MapToAttribute>();

			if (SimpleCheck.IsNull(map))
			{
				map = new MapToAttribute(targetProp.FieldType.GenericTypeArguments[0]);
			}

			if (sourceProp.FieldType.Name == typeof(List<>).Name)
			{
				dynamic dyValues = sourceObj;
				dynamic dyTargets = targetPropValue;
				MethodInfo add = targetProp.FieldType.GetMethod("Add");
				foreach (var dynamicItem in dyValues)
				{
					if (sourceProp.FieldType.GenericTypeArguments[0] == typeof(string) || !sourceProp.FieldType.GenericTypeArguments[0].IsClass)
					{
						add.Invoke(targetPropValue, new object[] { checkType.GetTargetValue(map, sourceProp.FieldType.GenericTypeArguments[0], targetProp.FieldType.GenericTypeArguments[0], dynamicItem) });
					}
					else
					{
						var subObject = Activator.CreateInstance(sourceProp.FieldType.GenericTypeArguments[0]);

						Map(dynamicItem, subObject);

						add.Invoke(targetPropValue, new object[] { subObject });
					}

					//if (method!=null)
					//{
					//	method.Invoke(taregetObj, new object[] {subObject} );
					//}
				}

			}
			else if (sourceProp.FieldType.Name == typeof(Dictionary<int, int>).Name)
			{
				dynamic dyMaps = sourceObj;
				dynamic dyTargetMapss = targetPropValue;
				MethodInfo add = targetProp.FieldType.GetMethod("Add");
				foreach (var mapItem in dyMaps)
				{
					if (sourceProp.FieldType.GenericTypeArguments[0] == typeof(string) || !sourceProp.FieldType.GenericTypeArguments[0].IsClass)
					{
						add.Invoke(targetPropValue, new object[] { mapItem.Key, checkType.GetTargetValue(map, sourceProp.FieldType.GenericTypeArguments[0], targetProp.FieldType.GenericTypeArguments[0], mapItem) });
					}
					else
					{
						var subObject = Activator.CreateInstance(sourceProp.FieldType.GenericTypeArguments[1]);
						Map(mapItem, subObject);
						add.Invoke(targetPropValue, new object[] { mapItem.Key, subObject });
					}
					//if (method != null)
					//{
					//	//key,value
					//	method.Invoke(taregetObj, new object[] { mapItem.Key, subObject });
					//}
				}
			}
			else
			{
				Map(sourceObj, targetPropValue);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <typeparam name="TSource"></typeparam>
		/// <param name="source"></param>
		/// <param name="member"></param>
		/// <returns></returns>
		private bool IsNull<TSource>(TSource source, PropertyInfo member)
		{
			bool result = false;
			SimpleCheck.TryCatch(() =>
			{
				result = checkType.IsNull(source, member);
			});
			return result;
		}
		/// <summary>
		/// 
		/// </summary>
		/// <typeparam name="TSource"></typeparam>
		/// <param name="source"></param>
		/// <param name="member"></param>
		/// <returns></returns>
		private bool IsNull<TSource>(TSource source, FieldInfo member)
		{
			bool result = false; ;
			SimpleCheck.TryCatch(() =>
			{
				result = checkType.IsNull(source, member);
			});
			return result;

		}


		private void SetPropery(MapToAttribute map, PropertyInfo pSource, PropertyInfo pTarget, object sourceValue, object Target)
		{
			if (pSource.PropertyType == pTarget.PropertyType)
			{
				pTarget.SetValue(Target, sourceValue);
			}
			else if (map != null && map.IsConvert)
			{
				checkType.SetValue(map, pSource, pTarget, sourceValue, Target);
			}

		}


		private void SetField(MapToAttribute map, FieldInfo pSource, FieldInfo pTarget, object sourceValue, object Target)
		{
			if (pSource.FieldType == pTarget.FieldType)
			{
				pTarget.SetValue(Target, sourceValue);
			}
			else if (map != null && map.IsConvert)
			{
				checkType.SetValue(map, pSource, pTarget, sourceValue, Target);
			}
		}


	}
}
